#include "../include/debug.h"
#include <iostream>

breakpoint points[32];

extern MemoryNode<dword> CodeMem[65536];
extern MemoryNode<byte> DataMem[65536];

extern bool RUNNING, ERROR, Zero, Sign;

extern word CodeH, CodeL;
extern IREG intRegs[128];
extern FREG floatReg[64];
extern DREG doublReg[64];

void AddBreak(breakpoint *list, word seg, word addr)
{
	for (int i = 0; i < 32; i++)
	{
		if (list[i].Points[1] == seg && list[i].Points[0] == addr)
			return;
		if (list[i].Points[1] == -1 && list[i].Points[0] == -1)
		{
			list[i].Points[1] = seg;
			list[i].Points[0] = addr;
			return;
		}
	}
}
void RemoveBreak(breakpoint *list, word seg, word addr)
{
	for (int i = 0; i < 32; i++)
	{
		if (list[i].Points[1] == seg && list[i].Points[0] == addr)
		{
			list[i].Points[1] = -1;
			list[i].Points[0] = -1;
			return;
		}
	}
}

void printer(char name)
{
	word argv[3] = {0};
	switch (name)
	{
	case 'i':
		std::cin >> argv[0];
		printf("Int Register %d : 0x%016I64x\n", argv[0] & 0x7f, intRegs[argv[0] & 0x7f].qvalue);
		break;
	case 'f':
		std::cin >> argv[0];
		printf("Float Register %d : %f\n", argv[0] & 0x3f, floatReg[argv[0] & 0x3f]);
		break;
	case 'd':
		std::cin >> argv[0];
		printf("Double Register %d : %f\n", argv[0] & 0x3f, doublReg[argv[0] & 0x3f]);
		break;
	case 'c':
		std::cin >> argv[0] >> argv[1] >> argv[2];
		for (int i = 0; i < argv[2]; i++)
			printf("Segment 0x%04x , Offset 0x%04x : 0x%08x\n", argv[0], argv[1] + i, CodeMem[argv[0]].data[argv[1] + i]);
		break;
	case 'm':
		std::cin >> argv[0] >> argv[1] >> argv[2];
		for (int i = 0; i < argv[2]; i++)
		{
			if (i % 16 == 0)
				printf("Data Segment 0x%04x , Offset 0x%04x : ", argv[0], argv[1] + i);
			if (i % 16 == 7)
				printf(" ");
			printf("%02hx ", DataMem[argv[0]].data[argv[1] + i]);
			if (i % 16 == 15)
				printf("\n");
		}
		break;
	case 'b':
		for (breakpoint *i = points; i->Addr != -1; i++)
			printf("Breakpoint %d : 0x%04x : 0x%04x\n", int(i - points), i->Points[1], i->Points[0]);
		break;
	case '?':
	case 'H':
	case 'h':
	default:
		printf("Usage:p target address,\'?\',\'h\',\'H\' to show this help message.\n");
		printf("***regs check***\n");
		printf("p i <register> : print int register\n");
		printf("p f <register> : print float register\n");
		printf("p d <register> : print double register\n");
		printf("***memory check***\n");
		printf("p c <segment> <offset> <count> : print code segment memory\n");
		printf("p m <segment> <offset> <count> : print data segment memory\n");
		printf("***breakpoint***\n");
		printf("p b : print breakpoint list\n");
		break;
	}
}
void debugger()
{
	char command, target;
	word argv[2] = {0};
	std::cin >> command;
	switch (command)
	{
	case 'b':
		std::cin >> argv[0] >> argv[1];
		AddBreak(points, argv[0], argv[1]);
		break;
	case 'n':
		selector(loader());
		break;
	case 'r':
		while (RUNNING && !ERROR)
			selector(loader());
		break;
	case 't':
		while (RUNNING && !ERROR)
		{
			selector(loader());
			for (breakpoint *i = points; i->Addr != -1; i++)
				if (i->Points[1] == CodeH && i->Points[0] == CodeL)
					return;
		}
		break;
	case 'd':
		std::cin >> argv[0] >> argv[1];
		RemoveBreak(points, argv[0], argv[1]);
		break;
	case 'p':
		std::cin >> target;
		printer(target);
		break;
	case 'q':
		exit(0);
		break;
	case '?':
	case 'h':
	case 'H':
	default:
		printf("Usage:command <args>,\'?\',\'h\',\'H\' to show this help message.\n");
		printf("b:b segment offset,add a new breakpoint.\n");
		printf("n:execute one instruction.\n");
		printf("r:run until error.\n");
		printf("t:run until breakpoint or error.\n");
		printf("d:d segment offset,delete a breakpoint.\n");
		printf("p:p target <address>,print target.\n");
		printf("q:quit.\n");
		break;
	}
}